package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.constants.message.PublishArticleConstants;
import com.heima.common.exception.CustException;
import com.heima.feigns.AdminFeign;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
     WmNewsMapper wmNewsMapper;
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Value("${file.oss.web-site}")

    String webSite;

    /**
     *  自动审核
     * @param id
     */
    @Override
    public void autoScanWmNews(Integer id) {
        log.info("自动审核方法触发了，审核的文章id为 {}",id);
        // 1. 根据id查询wmNews数据
        if (id==null){
            log.error("自动审核文章失败，文章id为空");
            CustException.cust(AppHttpCodeEnum.PARAM_REQUIRE,"查询id不能为空");
        }

        WmNews wmNews = this.wmNewsMapper.selectById(id);
        // 2. 判断存在  判断状态
        if (wmNews==null){
            log.error("自动审核文章失败，未查询自媒体文章信息id{}",id);
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"对应的文章信息不存在");
        }
        Short status = wmNews.getStatus();
        // 3. 判断状态是否为1  (消息幂等性)
        //NORMAL((short)0),SUBMIT((short)1),FAIL((short)2),ADMIN_AUTH((short)3),ADMIN_SUCCESS((short)4),SUCCESS((short)8),PUBLISHED((short)9);
        if (status.intValue()==WmNews.Status.SUBMIT.getCode()){
            // 3.1 抽取文章所有文本内容  及  所有图片
            //  Map <String, Object>   {  content :  文本内容  ,  images :  List<String>  图片路径集合}
            Map<String, Object> handleTextAndImage = handleTextAndImage(wmNews);
            //todo 3.2 DFA敏感词文本审核    不通过： 状态 2   通过下一步
            boolean scanSensitive = handleSensitive((String) handleTextAndImage.get("content"), wmNews);
            if (!scanSensitive)return;
            log.info("自动管理敏感词审核通过  ======= ");

            //todo 3.3 阿里云文本审核      不通过:  状态2   不确定: 状态3  通过下一步
            boolean isTextScan = handleTextScan((String) handleTextAndImage.get("content"), wmNews);
            if (!isTextScan) return;
            log.info("阿里云内容审核通过  ======= ");

            //todo 3.4 阿里云图片审核       不通过:  状态2   不确定: 状态3  通过下一步
            List<String> images = (List<String>) handleTextAndImage.get("images");
            if (images!=null){
                boolean imageScan = handleImageScan((List<String>) images, wmNews);
                if (!imageScan) return;
                log.info(" 阿里云图片审核通过  =======   ");
            }

            //todo 4. 判断文章发布时间是否大于当前时间   状态 8
            updateWmNes(wmNews,WmNews.Status.SUCCESS.getCode(),"审核成功");
            //TODO 5. 文章发布功能发送消息  通知发布文章
            //todo 5.1 获取定时发布时间
            long publishTime = wmNews.getPublishTime().getTime();
            //todo 5.2 获取此刻时间
            long nowTime = new Date().getTime();
            long reTime = publishTime - nowTime;
            if (reTime<=0){
                //todo 立即发布消息
                rabbitTemplate.convertAndSend(PublishArticleConstants.PUBLISH_ARTICLE_EXCHANGE,//todo 指定交换机
                        PublishArticleConstants.PUBLISH_ARTICLE_ROUTE_KEY, //todo 指定路由
                        wmNews.getId());  //todo 指定发送消息的文章
            }else {
                //todo 延时发送
                rabbitTemplate.convertAndSend(PublishArticleConstants.PUBLISH_ARTICLE_EXCHANGE,
                        PublishArticleConstants.PUBLISH_ARTICLE_DEAD_ROUTE_KEY,
                        wmNews.getId(),
                        (message) -> {
                    message.getMessageProperties().setExpiration(String.valueOf(reTime));
                    return message;
                        });
                log.info("延时发布文章通知成功发送，文章id : {} , 延时时间: {}毫秒",wmNews.getId(),reTime);
            }
        }

    }

    /**
     * 阿里图片审核
     * @param images
     * @param wmNews
     * @return
     */
    @Autowired
    GreenImageScan greenImageScan;
    private boolean handleImageScan(List<String> images, WmNews wmNews) {
        boolean flag=true;
        try {
            Map map = greenImageScan.imageUrlScan(images);
            String suggestion = (String)map.get("suggestion");
            switch (suggestion){
                case "block":
                    updateWmNes(wmNews,WmNews.Status.FAIL.getCode(),"图片中有违规内容，审核失败");
                    flag=false;
                    break;
                case "review":
                    updateWmNes(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"图片中有不确定内容，转为人工审核");
                    flag=false;
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云图片审核出现异常 , 原因:{}",e.getMessage());
            updateWmNes(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"阿里云内容服务异常，转为人工审核");
            flag = false;
        }
        return flag;
    }

    /**
     * 阿里云文本审核
     * @param content
     * @param wmNews
     * @return
     */
    @Autowired
    private GreenTextScan greenTextScan;

    private boolean handleTextScan(String content, WmNews wmNews) {
        boolean flag=true;
        try {
            Map map = greenTextScan.greenTextScan(content);
            String suggestion = (String) map.get("suggestion");
            // PASS  REVIEW  BLOCK
            switch (suggestion){
                case "block":
                    log.error("文本中有违规内容，审核失败");
                    updateWmNes(wmNews,WmNews.Status.FAIL.getCode(),"文本中有违规内容，审核失败");
                    flag=false;
                    break;
                case "review":
                    log.error("文本中有不确定内容，转为人工审核");
                    updateWmNes(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"文本中有不确定内容，转为人工审核");
                    flag=false;
                    break;

            }
        } catch (Exception e) {
            e.printStackTrace();
            flag=false;
            log.error("阿里云文本审核出现异常 , 原因:{}",e.getMessage());
            updateWmNes(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),"阿里云内容服务异常，转为人工审核");
            flag=false;
        }

        return flag;
    }


    /**
     * 抽取文章中的图片以及文本内容
     * @param wmNews
     * @return
     */
    private Map<String,Object> handleTextAndImage(WmNews wmNews) {
        //todo 获取图文内容
        String contentJSON = wmNews.getContent();
        if (StringUtils.isNotBlank(contentJSON)){
            log.error("自动审核文章失败，文章内容为空");
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"文章内容为空");
        }
        //todo 将JSON文章内容转为map集合
        List<Map> contentMaps = JSONArray.parseArray(contentJSON, Map.class);
        //TODO 1 抽取文章中所有文本     家乡很美   _hmtt_   国家伟大
        String content = contentMaps.stream()
                .filter(map -> "text".equals(map.get("type")))
                .map(map -> (String) map.get("value"))
                .collect(Collectors.joining("_hmtt_"));
        content= content + "_hmtt_" + wmNews.getTitle();

        //TODO 2. 抽取文章中所有图片   content :  全路径       images :  文件名称  + 访问前缀
        List<String> imageList = contentMaps.stream()
                .filter(map -> "image".equals(map.get("type")))
                .map(map -> (String) map.get("value"))
                .collect(Collectors.toList());
        if (StringUtils.isNotBlank(wmNews.getImages())){
            // 按照 逗号 切割封面字符串  得到数组   基于数组得到stream   将每一条数据都拼接一个前缀 收集成集合
            List<String> urls = Arrays.stream(wmNews.getImages().split(","))
                    .map(url -> webSite + url)
                    .collect(Collectors.toList());
            imageList.addAll(urls);
        }
        //TODO 3 去重
        imageList= imageList.stream().distinct().collect(Collectors.toList());
        Map result = new HashMap<>();
        result.put("content",content);
        result.put("images",imageList);
        return result;

    }
    /**
     *  基于DFA检测文章内容是否包含敏感词
     * @param content
     * @param wmNews
     * @return true: 审核通过  false: 失败
     */
    @Autowired
    private AdminFeign adminFeign;
    private boolean handleSensitive(String content, WmNews wmNews) {
        boolean flag=true;
        //todo 查询数据库中的敏感词
        ResponseResult<List<String>> queueAllSensitives = adminFeign.queueAllSensitives();
        //todo 判断状态
        if (queueAllSensitives.getCode().intValue()!=0){
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR,queueAllSensitives.getErrorMessage());
        }
        //todo 获取查询的数据
        List<String> allSensitivesData = queueAllSensitives.getData();
        //todo 将敏感词存放到DFA数据模型
        SensitiveWordUtil.initMap(allSensitivesData);
        //todo 检测敏感词
        Map<String, Integer> resultMap = SensitiveWordUtil.matchWords(content);
        if (resultMap!=null&&resultMap.size()>0){
            //todo 不通过： 状态 2   通过下一步
            updateWmNes(wmNews,WmNews.Status.FAIL.getCode(),"文章内容包含敏感词："+resultMap);
            flag=false;
        }
        return flag;
    }
    /**
     * 修改文章状态
     * @param wmNews
     * @param status
     * @param reason
     */
    private void updateWmNes(WmNews wmNews, short status, String reason) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }
}
